import {
    App,
    ButtonGroupControl,
    DOM,
    Entity,
    EventModule,
    FillExtrusionsEntity,
    MeshEntity,
    MousePositionControl,
    PolygonsEntity,
    PolylinesEntity,
    ResManager,
    creataMeasureRuler,
    fromWorld,
    makeObject3DUiConfig,
    toDist,
    toWorld
} from "vjmap3d";
import { env } from "./env";
import { GeoPoint, entColorToHtmlColor } from "vjmap";
import { BufferAttribute, BufferGeometry, Color, DoubleSide, Group, Mesh, MeshStandardMaterial, Plane, PlaneGeometry, Vector3 } from "three";
import { Lut } from "three/examples/jsm/math/Lut.js";
import { queryFeatures } from "./query";

const createMesh = (dataMinZ: number, dataMaxZ: number, points: [number, number, number][], indices: number[], prop: any) => {
    let worldCoords: number[] = [];
    let lut = new Lut();
    
    let moveZ = 0
    if (env.baseZ !== 0) { // 如果为零时，按之前的高度绘制，否则都移至水平线上面
        moveZ = env.baseZ - dataMinZ;
    }
    lut.setMax(dataMaxZ);
    lut.setMin(dataMinZ);
    let colorArrays = [];
    //let worldPosArray = [];
    for (let k = 0; k < points.length; k++) {
        let cadPos: any = [];
        cadPos.push(points[k][0]);
        cadPos.push(points[k][1]);
        let z = points[k][2] + moveZ;
        colorArrays.push(...lut.getColor(points[k][2]).toArray());
        cadPos.push(z * env.scaleZ);

        let worldPos = toWorld(cadPos);
        worldCoords.push(...worldPos);
        //worldPosArray.push(worldPos)
    }

    let geometry = new BufferGeometry();
    
    geometry.setAttribute("position", new BufferAttribute(new Float32Array(worldCoords), 3));
    geometry.setIndex(new BufferAttribute(new Uint32Array(indices), 1));
    geometry.setAttribute("color", new BufferAttribute(new Float32Array(colorArrays), 3));
    // 将 UV 坐标设置到几何体 如果要纹理贴图，需要给定uv坐标，uv坐标得根据实际情况计算，下面的可供参考
    // let uvs = new Float32Array(worldPosArray.length * 2);
    // let xmin = Math.min(...worldPosArray.map(p => p.x));
    // let xmax = Math.max(...worldPosArray.map(p => p.x))
    // let ymin = Math.min(...worldPosArray.map(p => p.y))
    // let ymax = Math.max(...worldPosArray.map(p => p.y))
    // let zmin = Math.min(...worldPosArray.map(p => p.z))
    // let zmax = Math.max(...worldPosArray.map(p => p.z))
    // for(let c = 0; c < worldPosArray.length; c++) {
    //     // 计算 UV 坐标
    //     const u = (worldPosArray[c].x - xmin) / (xmax - xmin);
    //     const v = app.isMapMode ?
    //     (worldPosArray[c].y - ymin) / (ymax - ymin): 
    //     (worldPosArray[c].z - zmin) / (zmax - zmin);

    //     // 设置 UV 坐标
    //     uvs[c * 2] = u;
    //     uvs[c * 2 + 1] = v;
    // }
    // geometry.setAttribute('uv', new BufferAttribute(uvs, 2));
    geometry.computeVertexNormals();
    //   console.log(coords,triangles )
    let mat = new MeshStandardMaterial({
        color: new Color(entColorToHtmlColor(prop.color, env.darkTheme)),
        //map: ResManager.loadTextureLinear("./uv_grid_opengl.jpg"), // 如果有uv坐标要进行纹理贴图
        vertexColors: false,
        // wireframe: true,
        side: DoubleSide
    });
    if (prop.alpha && prop.alpha != 255) {
        mat.transparent = true;
        mat.opacity = prop.alpha / 255;
    }
    let mesh = new Mesh(geometry, mat);
    return {
        mesh,
        moveZ
    }
}
const drawPolyMesh = async (app: App, parent: Group) => {
    // 查找图中所有的三维实体坐标
    let query = await queryFeatures(app.svc, {
        // 支持的实体类型（列出一些支持的三维实体类型） https://vjmap.com/guide/svrStyleVar.html#%E6%94%AF%E6%8C%81%E7%9A%84cad%E5%AE%9E%E4%BD%93%E7%B1%BB%E5%9E%8B
        condition: `name='31' or name='32' or name='33' or name='34' or name='35'`,
        fields: "objectid,name,points,indices,color,data3d,alpha",
        limit: 100000
    }, true);
    let results = query.result;
    if (!results)  {
        // 先绘制三维线 
        let res = await drawPolylines(app, parent);
        return res?.meshs
    }
    results = results.filter((r : any)=> r.points != "")
    let points = results.map((e: any) => {
        let pts = e.points.split(";");
        return pts.map((p: any) => {
            let pt = GeoPoint.fromString(p);
            pt.z ??= 0;
            return pt;
        }) as GeoPoint[];
    });
    let indices = results.map((e: any) => {
        return e.indices
            .replaceAll(";", ",")
            .split(",")
            .map((t: string) => +t);
    });

    let meshs = [];
    // 求出所有数据的最大最小值
    let dataMaxZArr: number[] = [], dataMinZArr: number[] = [];
    for (let n = 0; n < points.length; n++) {
        let maxZ = Math.max(...points[n].map((k: GeoPoint) => k.z));
        let minZ = Math.min(...points[n].map((k: GeoPoint) => k.z));
        dataMaxZArr.push(maxZ);
        dataMinZArr.push(minZ);
    }
    let dataMaxZ = Math.max(...dataMaxZArr)
    let dataMinZ = Math.min(...dataMinZArr)

    // 先绘制三维线 
    let res = await drawPolylines(app, parent, dataMinZ, dataMaxZ);
    dataMaxZ = res?.dataMaxZ ?? dataMaxZ;
    dataMinZ = res?.dataMinZ ?? dataMinZ;
    if (res?.meshs) meshs.push(...res.meshs)
    
    for (let n = 0; n < points.length; n++) {
        let ret = createMesh(dataMinZ, dataMaxZ, points[n].map((p: any) => [p.x, p.y, p.z]), indices[n], results[n])
        let entity = MeshEntity.fromObject3d(ret.mesh);
        entity.addTo(parent, app);
        entity.add(EventModule, {
            hoverSelect: true,
            clickCallback: (_, isClick) => {
                if (!isClick) return;
                app.logInfo(`实体类型: ${results[n].name}, 实体ObjectID: ${results[n].objectid}`)
            }
        });
        meshs.push({
            mesh: ret.mesh,
            moveZ: ret.moveZ
        });
    }
    return meshs;
};

const drawPolylines = async (app: App, parent: Group, dataMinZ?: number, dataMaxZ?: number) => {
    // 查找图中所有的三维线坐标
    let query = await queryFeatures(app.svc, {
        // 支持的实体类型（列出一些支持的三维实体类型） https://vjmap.com/guide/svrStyleVar.html#%E6%94%AF%E6%8C%81%E7%9A%84cad%E5%AE%9E%E4%BD%93%E7%B1%BB%E5%9E%8B
        condition: `name='1' or name='2' or name='3' or name='4' or name='5'`,
        fields: "",
        includegeom: true, // 是否返回几何数据,为了性能问题，realgeom为false时，如果返回条数大于1.只会返回每个实体的外包矩形，如果条数为1的话，会返回此实体的真实geojson；realgeom为true时每条都会返回实体的geojson
        realgeom: true,
        toMapCoordinate: true,
        limit: 100000
    }, true);
    let results = query.result;
    if (!results) return;
   
    let zArr = dataMinZ === undefined ? [] : [dataMinZ, dataMaxZ];
    results.forEach((item: any) => {
        item.alpha = item.alpha / 255;
        item.clr = entColorToHtmlColor(item.color, env.darkTheme);
        item.geojson = JSON.parse(item.geojson);
        const pts = item.points.split(";");
        const points = [];
        let hasZ = false;
        for(let p of pts) {
            if (p.indexOf(",") > 0) {
                let pt = GeoPoint.fromString(p)
                points.push(pt);
                if (pt.z !== undefined) {
                    zArr.push(pt.z)
                    hasZ = true;
                }
            }
        }
        if (item.elevation !== undefined) {
            zArr.push(item.elevation)
            if (item.thickness !== undefined) {
                zArr.push(item.elevation + item.thickness)
            }
        }
        item.points = points;
        item.hasZ = hasZ;
    })
    // 求z的最大最小值
    // @ts-ignore
    dataMaxZ = Math.max(...zArr)
    // @ts-ignore
    dataMinZ = Math.min(...zArr)

    let moveZ = 0
    if (env.baseZ !== 0) { // 如果为零时，按之前的高度绘制，否则都移至水平线上面
        moveZ = env.baseZ - dataMinZ;
    }

    let meshs: any[] = [];

    let dataPolyline = [];
    let dataPolygon = [];
    let dataFillExtrusions = [];
    for (let r = 0; r < results.length; r++) {
        for (let i = 0; i < results[r].geojson.geometries.length; i++) {
            let feature = results[r].geojson.geometries[i];
            let elevation = results[r].elevation; // 高度
            if ((feature.type == "LineString")) {
                if (results[r].hasZ) {
                    // 如果有z值，用坐标序列
                    dataPolyline.push({
                        coordinates: results[r].points.map((c: any) => toWorld([c.x, c.y, (c.z + moveZ) * env.scaleZ ]).toArray()),
                        color: results[r].clr,
                        lineWidth:  1,
                        lineOpacity: results[r].alpha,
                        dashed: false,
                        objectid: results[r].objectid,
                        name: results[r].name,
                    })
                }
                else {
                    dataPolyline.push({
                        coordinates: feature.coordinates.map((c: any) => toWorld([c[0], c[1], ((elevation ?? 0)+ moveZ) * env.scaleZ  ]).toArray()),
                        color: results[r].clr,
                        lineWidth:  1,
                        lineOpacity: results[r].alpha,
                        dashed: false,
                        objectid: results[r].objectid,
                        name: results[r].name,
                    })
                }
            } else if ((feature.type == "Polygon")) {
                if (results[r].thickness && results[r].thickness > 0) {
                    // 有高度，需要拉伸
                    dataFillExtrusions.push({
                        coordinates: feature.coordinates.map((c: any) => c.map((s: any) => {
                            let vec3 = toWorld([s[0], s[1]]).toArray();
                            return [vec3[0], vec3[2]]
                        })),
                        color: results[r].clr,
                        opacity: results[r].alpha,
                        objectid: results[r].objectid,
                        baseHeight:  toDist(((elevation ?? 0)+ moveZ) * env.scaleZ),
                        name: results[r].name,
                        extrude: {
                            depth: toDist(results[r].thickness)
                        }
                    })
                } else {
                    dataPolygon.push({
                        coordinates: feature.coordinates.map((c: any) => c.map((s: any) => {
                            return toWorld([s[0], s[1],  ((elevation ?? 0)+ moveZ) * env.scaleZ]).toArray();
                        })),
                        color: results[r].clr,
                        opacity: results[r].alpha,
                        objectid: results[r].objectid,
                        name: results[r].name,
                    })
                }
               
            }
        }
    }
    if (dataPolyline.length > 0) {
        let polylines = new PolylinesEntity({
            data: dataPolyline,
            highlightStyle: {
                vertexColors: false,
                color: 0xFFFF00
            },
        })
        polylines.addTo(parent, app);
        polylines.pointerEvents = true;
      
        // 
        polylines.on("mouseover", (e: any) => {
            if (e?.intersection?.faceIndex !== undefined) {
                let itemData = polylines.getItemDataByFaceIndex(e?.intersection?.faceIndex);
                if (itemData) {
                    // objectid相同的都选上
                    let entities = polylines.getData().filter(item => item.objectid == itemData.objectid)
                    entities.forEach(e => e.id !==undefined &&  polylines.setItemHighlight(e.id, true))
                }
            }            
        })
        polylines.on("mouseout", () => {
            polylines.clearHighlight()
        })
        polylines.on("click", (e: any) => {
            if (e?.intersection?.faceIndex !== undefined) {
                let itemData = polylines.getItemDataByFaceIndex(e?.intersection?.faceIndex);
                if (itemData) {
                    // objectid相同的都选上
                    app.logInfo(`实体类型: ${itemData.name}, 实体ObjectID: ${itemData.objectid}`)
                }
            }
        })
        meshs.push({
            mesh: polylines.getPolylines(),
            moveZ: moveZ
        })
    }
   

    if (dataPolygon.length == 0) {
        // 
        let polygons = new PolygonsEntity({ // PolygonsEntity
            data: dataPolygon ,
            showVertex: false,
        })
        polygons.addTo(parent, app)
        //
        polygons.pointerEvents = true;
        polygons.on("mouseover", (e: any) => {
            if (e?.intersection?.faceIndex !== undefined) {
                let itemData = polygons.getItemDataByFaceIndex(e?.intersection?.faceIndex);
                if (itemData) {
                    // objectid相同的都选上
                    let entities = polygons.getData().filter(item => item.objectid == itemData.objectid)
                    entities.forEach(e => e.id !==undefined && polygons.setItemHighlight(e.id, true))
                }
            }
        })
        polygons.on("mouseout", () => {
            polygons.clearHighlight()
        })
        polygons.on("click", (e: any) => {
            if (e?.intersection?.faceIndex !== undefined) {
                let itemData = polygons.getItemDataByFaceIndex(e?.intersection?.faceIndex);
                if (itemData) {
                    // objectid相同的都选上
                    app.logInfo(`实体类型: ${itemData.name}, 实体ObjectID: ${itemData.objectid}`)
                }
            }
        })
        meshs.push({
            mesh: polygons.getPolygons(),
            moveZ: moveZ
        })
    }
    

    // 
    if (dataFillExtrusions.length > 0) {
        let fillExtrusions = new FillExtrusionsEntity({ // PolygonsEntity
            // @ts-ignore
            data: dataFillExtrusions ,
            showVertex: false,
        })
        fillExtrusions.addTo(parent, app)
        //
        fillExtrusions.pointerEvents = true;
        fillExtrusions.on("mouseover", (e: any) => {
            if (e?.intersection?.faceIndex !== undefined) {
                let itemData = fillExtrusions.getItemDataByFaceIndex(e?.intersection?.faceIndex);
                if (itemData) {
                    // objectid相同的都选上
                    let entities = fillExtrusions.getData().filter(item => item.objectid == itemData.objectid)
                    entities.forEach(e => e.id !==undefined && fillExtrusions.setItemHighlight(e.id, true))
                }
            }
        })
        fillExtrusions.on("mouseout", () => {
            fillExtrusions.clearHighlight()
        })
        fillExtrusions.on("click", (e: any) => {
            if (e?.intersection?.faceIndex !== undefined) {
                let itemData = fillExtrusions.getItemDataByFaceIndex(e?.intersection?.faceIndex);
                if (itemData) {
                    // objectid相同的都选上
                    app.logInfo(`实体类型: ${itemData.name}, 实体ObjectID: ${itemData.objectid}`)
                }
            }
        })
        meshs.push({
            mesh: fillExtrusions.getFillExtrusions(),
            moveZ: moveZ
        })
    }
    
    
    return {
        dataMinZ,
        dataMaxZ,
        meshs
    }
    
   // return meshs;
};
const draw3dEntity = async (app: App) => {
    let group = new Group();
    app.scene.add(group);

    let addMeshDatas = []
    let polyMeshs = await drawPolyMesh(app, group);
    // @ts-ignore
    addMeshDatas.push(...polyMeshs ?? [])
   
    let mousePositionControl: MousePositionControl;
    const showMousePositionControl = () => {
        if (mousePositionControl) return;
        mousePositionControl = new MousePositionControl({
            UnProjectModes: app.isMapMode ? [true] : [true],
            labelFormat: (x, y, z, _, retIntersectObject) => {
                let cad = fromWorld([x, y, z]);
                let index = addMeshDatas.findIndex(m => retIntersectObject?.object?.object == m.mesh);
                if (index >= 0) {
                    // 如果是在mesh上
                    z = cad[2] / env.scaleZ  - addMeshDatas[index].moveZ;
                    return `${cad[0].toFixed(4)}, ${cad[1].toFixed(4)}, ${z.toFixed(4)}`;
                } else {
                    return `${cad[0].toFixed(4)}, ${cad[1].toFixed(4)}`;
                }
            }
        });
        app.addControl(mousePositionControl);
    };
    const hideMousePositionControl = () => {
        if (!mousePositionControl) return;
        app.removeControl(mousePositionControl);
        // @ts-ignore
        mousePositionControl = null;
    };
    if (env.showMousePositionControl) {
        showMousePositionControl();
    }

      
    // @ts-ignore
    if (addMeshDatas.length == 0) {
        app.logInfo("没有相到图中的三维多段线或多面网格实体或相关的三维实体，无法自动生成三维模型", "warn", 10000)
    }
    return {
        group,
        meshs: addMeshDatas.map(m => m.mesh),
        showMousePositionControl,
        hideMousePositionControl
    };
};

export const initButtonGroup = async (app: App) => {
    let draw = await draw3dEntity(app);

    // 底图隐藏/显示
    let isHide = false;
    const showHideMap = () => {
        if (app.isMapMode) {
            if (isHide) {
                app.map.showSource("raster-source");
            } else {
                app.map.hideSource("raster-source");
            }
            isHide = !isHide;
        } else {
            app.mapViewEntity.visible = !app.mapViewEntity.visible;
        }
    }

    // 渐变色开/关
    const showHideVertexColors = () => {
        draw?.meshs.forEach(mesh => {
            if (!mesh || !mesh.material) return;
            mesh.material.vertexColors = !mesh.material.vertexColors
            mesh.material.needsUpdate = true
        })
    }

    // 线宽模式开/关
    const showHideWireframe = () => {
        draw?.meshs.forEach(mesh => {
            if (!mesh) return;
            mesh.material.wireframe = !mesh.material.wireframe
        })
    }
    let control = new ButtonGroupControl({
        buttons: [
            {
                id: "hidemap",
                html: "底图隐藏/显示",
                title: "底图隐藏/显示",
                style: {
                    width: "130px"
                },
                onclick: async () => {
                    showHideMap()
                }
            },
            {
                id: "vertcolors",
                html: "渐变色开/关",
                title: "渐变色开/关",
                style: {
                    width: "130px"
                },
                onclick: async () => {
                    showHideVertexColors();
                }
            },
            {
                id: "wireframe",
                html: "线宽模式开/关",
                title: "线宽模式开/关",
                style: {
                    width: "130px"
                },
                onclick: async () => {
                    showHideWireframe();
                }
            },
            {
                id: "mouseposctrl",
                html: "鼠标位置/显示",
                title: "鼠标位置/显示",
                style: {
                    width: "130px"
                },
                onclick: async () => {
                    if (env.showMousePositionControl) {
                        draw?.hideMousePositionControl();
                    } else {
                        draw?.showMousePositionControl();
                    }
                    env.showMousePositionControl = !env.showMousePositionControl;
                }
            },
            {
                id: "customModel",
                html: "放置自定义模型",
                title: "",
                style: {
                    width: "110px"
                },
                onclick: async () => {
                    app.logInfo("请选择本地的模型文件，拖放至场景中相应位置", "success", 5000)
                }
            },
            {
                id: "editpos",
                html: "编辑物体位置",
                title: "",
                style: {
                    width: "110px"
                },
                onclick: async () => {
                    app.setCurrentTool("transform", {
                        mode: "translate",
                        // showX: ["translate", "scale"], // 平移和缩放时显示x轴
                        // showY: app.isMapMode ? ["translate", "scale"] : ["rotate", "scale"],
                        // showZ: !app.isMapMode ? ["translate", "scale"] : ["rotate", "scale"],
                        clickNoEntityExit: true
                    });
                    showMessageTip(app,  "按 W 键切换平移模式, E 键切换旋转模式, R 键切换缩放模式, shfit 键时进行微调,  X Y Z 键分别对此轴进行显示或隐藏");
                }
            },
            {
                id: "editprop",
                html: "编辑物体属性",
                title: "",
                style: {
                    width: "110px"
                },
                onclick: async () => {
                    let opts = {
                        highlightUseBoxHelper: true,
                        highlightOpacity: 0,
                        pickCallBack: async (param: any) => {
                            const ui = await app.getConfigPane({
                                style: {
                                    right: "160px"
                                }
                            })
                            ui.reset();
                            if (param.curPick) {
                                ui.setVisible(true)
                                let config;
                                if (app.Input.getKeyPressed("ControlLeft") && param.curPick.intersection?.object) {
                                    // 如果按往了ctrl键，则只选择中当前选择的
                                    let obj = param.curPick.intersection?.object;
                                    config = makeObject3DUiConfig(obj)
                                } else {
                                    config = param.curPick.target.uiConfig;
                                }
                                ui.appendChild(config)
                            } else {
                                ui.setVisible(false)
                                // 退出
                                app.setCurrentTool("")
                            }
                        }
                    }
                    app.setCurrentTool("pick", opts)
                }
            },
            {
                id: "measureruler",
                html: "测量标尺",
                title: "",
                style: {
                    width: "110px"
                },
                onclick: async () => {
                    if (!app.isMapMode) {
                        showMessageTip(app, "可点击右键选择投影方式")
                    }
                    let line = await app.actionDrawLineSting({
                        pointMaxCount: 2
                    });
                    if (line.isCancel) return;
                    creataMeasureRuler(app, {
                        startPoint: line.data.coordinates[0],
                        endPoint: line.data.coordinates[1],
                        // @ts-ignore
                        textStyle: {
                            billboard: false
                        }
                    });
                }
            },
            {
                id: "clip",
                html: "剖切",
                title: "",
                style: {
                    width: "110px"
                },
                onclick: async () => {
                      // 允许裁剪
                    app.renderer.localClippingEnabled = true;
                    let groupEntity = Entity.attchObject(draw.group, true, false, app);
                    let box3d = groupEntity.getBoundingBox()
                    const clippingPlane = new Plane(new Vector3(0, 0, -1), (box3d.min.z  + box3d.max.z) / 2)
                    groupEntity.node.traverse((obj: any) => {
                        if (obj && obj.material) {
                            obj.material.clippingPlanes = [clippingPlane]
                        }
                    })
                    app.logInfo("可按 E 键旋转平面，再按 W 切换至平移 对另外的平面进行剖切", "info", 60000)
                    // 创建一个可视化平面网格
                    const plane = new Mesh(new PlaneGeometry(0.1, 0.1), new MeshStandardMaterial({ color: 0xffffff}));
                    plane.position.z = (box3d.min.z  + box3d.max.z) / 2
                    plane.rotateY(Math.PI)
                    app.scene.add(plane)
                    await app.transformObject({
                        target: plane,
                        clickNoSelfEntityExit: true,
                        clickEntityAttach: false,
                        dragCallBack: () => {
                            const newPlaneNormal = new Vector3();
                            plane.getWorldDirection(newPlaneNormal);
                            clippingPlane.normal.copy(newPlaneNormal);
                            clippingPlane.constant = - plane.position.dot(newPlaneNormal);
                        }
                    })
                    // 结束取消
                    app.scene.remove(plane)
                    groupEntity.node.traverse((obj: any) => {
                        if (obj && obj.material) {
                            obj.material.clippingPlanes = []
                        }
                    })
                    app.renderer.localClippingEnabled = false;
                }
            },
            {
                id: "switchmode",
                html: !app.isMapMode ? "2D图" : "3D图",
                title: !app.isMapMode ? "以2D图3D做为图层的形式打开查看" : "以3D形式打开查看",
                round: true,
                style: { width: "40px" },
                onclick: async () => {
                    let href = window.location.href;
                    if (href.indexOf("?") == -1) href += "?";
                    href = href.replace("&map2d=true", "");
                    href = href.replace("&map2d=false", "");
                    href = href.replace("map2d=true", "");
                    href = href.replace("map2d=false", "");
                    if (app.isMapMode) {
                        href += "&map2d=false";
                    } else {
                        href += "&map2d=true";
                    }
                    window.open(href);
                }
            }
        ]
    });
    app.addControl(control, "top-right");

    if (env.showBaseMap === false) {
        showHideMap()
    }
    if (env.showVertexColors === true) {
        showHideVertexColors()
    }
    if (env.showWireframe === true) {
        showHideWireframe()
    }
    enableDragModel(app);
};

export const showMessageTip = (app: App, message?: string) => {
    if (!message) return;
    let div = document.createElement("div");
    div.innerHTML = `<h4 style = "position:absolute;color:${
        env.darkTheme ? "yellow" : "blue"
    };top:30px;left:100px">${message}</h4>`;
    app.container.appendChild(div);
    setTimeout(() => DOM.remove(div), 5000);
};


// 拖放一个模型至场景中
export const enableDragModel = async (app: App) => {
    // 支持拖放
    const dropZone = app.container;
    // Prevent default drag behaviors
    ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
        dropZone.addEventListener(eventName, preventDefaults, false);
    });

    function preventDefaults(e: any) {
        e.preventDefault();
        e.stopPropagation();
    }

    // Highlight drop area when item is dragged over it
    ['dragenter', 'dragover'].forEach(eventName => {
        dropZone.addEventListener(eventName, () => {
            dropZone.classList.add('dragover');
        }, false);
    });

    ['dragleave', 'drop'].forEach(eventName => {
        dropZone.addEventListener(eventName, () => {
            dropZone.classList.remove('dragover');
        }, false);
    });

    // Handle dropped files
    dropZone.addEventListener('drop', handleDrop, false);

    async function handleDrop(e: any) {
        const dt = e.dataTransfer;
        const files = dt.files;

        // 获取文件类型后缀
        let ext = files[0].name.substring(files[0].name.indexOf(".") + 1).toLowerCase()
        // Only handle the first file for this example
        if (files.length > 0) {
            const file = files[0];
            const url = URL.createObjectURL(file);
            
            let ent = await ResManager.loadModel(url, {
                splitSubEntity: true,
                size:  5,
                //anchor: "front-bottom",
                position: app.unproject(e.x, e.y), // 当前拖放的位置
                fileType: ext
            });
            ent.addTo(app);

            // 属性面板
            const ui = await app.getConfigPane({
                style: {
                    right: "160px"
                }
            })
            ui.setVisible(true);
            let config = makeObject3DUiConfig(ent.node)
            ui.appendChild(config)

            // 编辑
            let options = {
                target: ent.node,
                clickNoSelfEntityExit: true,
                clickNoEntityExit: true, 
                rightClickConfirmExit: true // 右键退出编辑
            }
            await app.transformObject(options)

            ui.setVisible(false);
        }
    } 
}